//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package sw_dao

import (
	"context"

	"atomgit.com/openlinksaas-org/api-server/dao/db_ns"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/sw_store_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type SoftWareInfoDbItem struct {
	SwId        string   `bson:"_id" json:"_id"`
	SwName      string   `bson:"swName" json:"swName"`
	SwDesc      string   `bson:"swDesc" json:"swDesc"`
	CateId      string   `bson:"cateId" json:"cateId"`
	Weight      uint32   `bson:"weight" json:"weight"`
	Recommend   bool     `bson:"recommend" json:"recommend"`
	OsList      []uint32 `bson:"osList" json:"osList"`
	DownloadUrl string   `bson:"downloadUrl" json:"downloadUrl"`
	IconFileId  string   `bson:"iconFileId" json:"iconFileId"`
	CreateTime  int64    `bson:"createTime" json:"createTime"`
	UpdateTime  int64    `bson:"updateTime" json:"updateTime"`
}

func (item *SoftWareInfoDbItem) ToSoftWareInfo() *sw_store_api.SoftWareInfo {
	osList := []sw_store_api.OS_TYPE{}
	for _, osType := range item.OsList {
		osList = append(osList, sw_store_api.OS_TYPE(osType))
	}
	return &sw_store_api.SoftWareInfo{
		SwId:        item.SwId,
		SwName:      item.SwName,
		SwDesc:      item.SwDesc,
		CateId:      item.CateId,
		Weight:      item.Weight,
		Recommend:   item.Recommend,
		OsList:      osList,
		DownloadUrl: item.DownloadUrl,
		IconFileId:  item.IconFileId,
		CreateTime:  item.CreateTime,
		UpdateTime:  item.UpdateTime,
	}
}

type _SoftwareDao struct {
	mc *mongo.Collection
}

func newSoftwareDao(db *mongo.Database) (*_SoftwareDao, error) {
	mc := db.Collection(db_ns.DB_NS_SW_STORE + "software")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"weight", 1}, {"updateTime", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_SoftwareDao{mc: mc}, nil
}

func (db *_SoftwareDao) Insert(ctx context.Context, dbItem *SoftWareInfoDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_SoftwareDao) Update(ctx context.Context, dbItem *SoftWareInfoDbItem) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": dbItem.SwId}, bson.M{"$set": dbItem})
	return err
}

func (db *_SoftwareDao) Exist(ctx context.Context, swId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"_id": swId})
	return count > 0, err
}

func (db *_SoftwareDao) Get(ctx context.Context, swId string) (*SoftWareInfoDbItem, error) {
	retItem := &SoftWareInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"_id": swId}).Decode(retItem)
	return retItem, err
}

func (db *_SoftwareDao) Remove(ctx context.Context, swId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"_id": swId})
	return err
}

func (db *_SoftwareDao) genListQuery(listParam *sw_store_api.ListSoftWareParam) bson.M {
	query := bson.M{}
	if listParam.FilterbyOsType {
		query["osList"] = uint32(listParam.OsType)
	}
	if listParam.FilterByCateId {
		query["cateId"] = listParam.CateId
	}
	if listParam.FilterByRecommend {
		query["recommend"] = listParam.Recommend
	}
	return query
}

func (db *_SoftwareDao) Count(ctx context.Context, listParam *sw_store_api.ListSoftWareParam) (uint32, error) {
	query := db.genListQuery(listParam)
	count, err := db.mc.CountDocuments(ctx, query)
	return uint32(count), err
}

func (db *_SoftwareDao) CountByCate(ctx context.Context, cateId string) (uint32, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"cateId": cateId})
	return uint32(count), err
}

func (db *_SoftwareDao) List(ctx context.Context, listParam *sw_store_api.ListSoftWareParam, offset, limit int64) ([]*SoftWareInfoDbItem, error) {
	query := db.genListQuery(listParam)
	cursor, err := db.mc.Find(ctx, query, options.Find().SetSkip(offset).SetLimit(limit).SetSort(bson.D{{"weight", -1}, {"updateTime", -1}}))
	if err != nil {
		return nil, err
	}
	retList := []*SoftWareInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_SoftwareDao) ListAll(ctx context.Context) ([]*SoftWareInfoDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{}, options.Find().SetSort(bson.D{{"weight", -1}, {"updateTime", -1}}))
	if err != nil {
		return nil, err
	}
	retList := []*SoftWareInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}
